// -----------------------------------------------------------------------
//  <copyright file="SetRoleCommand.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2025 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2025-03-04 23:03</last-date>
// -----------------------------------------------------------------------

using DaprPlus.Identity.Domain.Entities;
using DaprPlus.Identity.Application.Identity.Users.Dtos;

using Microsoft.AspNetCore.Identity;


namespace DaprPlus.Identity.Application.Identity.Users.Commands;

[AuthConfig(typeof(User), ResourceAccessType.RoleLimit, "SetRole")]
public class SetRoleCommand : IRequest<ApiResult>, ICommand
{
    public long UserId { get; set; }

    public required UserRoleInDto[] Roles { get; set; }
}

public class SetRoleCommandHandler(IServiceProvider provider) : IRequestHandler<SetRoleCommand, ApiResult>
{
    public async Task<ApiResult> Handle(SetRoleCommand request, CancellationToken cancellationToken)
    {
        var userManager = provider.GetRequiredService<UserManager<User>>();

        // 查找用户
        var repository = provider.GetRepository<User>();
        var spec = new UserByIdSpec<User>(request.UserId).And(new UserIncludeRoleSpec<User>());
        var user = await repository.GetAsync(spec, cancellationToken);
        if (user == null)
        {
            return new ApiResult(ApiResultType.Error, $"用户Id为 {request.UserId} 的用户不存在");
        }

        if (user.IsSystem)
        {
            return new ApiResult(ApiResultType.Error, "系统用户不能更改角色分配");
        }

        // 获取用户当前的有效角色
        var currentRoles = await userManager.GetValidRolesAsync(user, cancellationToken);

        // 获取新角色名称列表
        var newRoleNames = request.Roles.Select(r => r.RoleName).ToArray();

        // 移除不在新角色列表中的角色
        var rolesToRemove = currentRoles.Where(r => !newRoleNames.Contains(r)).ToArray();
        if (rolesToRemove.Length > 0)
        {
            var removeResult = await userManager.RemoveFromRolesAsync(user, rolesToRemove);
            if (!removeResult.Succeeded)
            {
                return new ApiResult(ApiResultType.Error, removeResult.Errors.First().Description);
            }

            await userManager.UpdateSecurityStampAsync(user);
        }

        // 添加新角色，每个角色支持独立的时间参数
        foreach (var roleDto in request.Roles)
        {
            if (!currentRoles.Contains(roleDto.RoleName))
            {
                var addResult = await userManager.AddToRoleWithTimeAsync(user, roleDto.RoleName,
                    roleDto.BeginTime, roleDto.EndTime, cancellationToken);
                if (!addResult.Succeeded)
                {
                    return new ApiResult(ApiResultType.Error, addResult.Errors.First().Description);
                }
            }
        }

        await repository.UpdateAsync(user, cancellationToken);

        return new ApiResult(ApiResultType.Success, "用户角色设置成功");
    }
}

public class SetRoleCommandValidator : AbstractValidator<SetRoleCommand>
{
    public SetRoleCommandValidator()
    {
        RuleFor(x => x.UserId).GreaterThan(0).WithMessage("用户Id必须大于0");
        RuleFor(x => x.Roles).NotNull().WithMessage("角色列表不能为空");
        RuleFor(x => x.Roles).Must(roles => roles.Length > 0).WithMessage("至少需要一个角色");

        // 验证每个角色的时间逻辑
        RuleForEach(x => x.Roles).ChildRules(role =>
        {
            role.RuleFor(r => r.RoleName).NotEmpty().WithMessage("角色名称不能为空");
            role.RuleFor(r => r.EndTime)
                .GreaterThan(r => r.BeginTime)
                .When(r => r.BeginTime.HasValue && r.EndTime.HasValue)
                .WithMessage("过期时间必须大于生效时间");
        });
    }
}

